package com.innovation.ic.cc.base.service.cc.impl;

import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.JSONObject;
import com.google.common.base.Strings;
import com.innovation.ic.b1b.framework.util.HttpUtils;
import com.innovation.ic.cc.base.handler.cc.*;
import com.innovation.ic.cc.base.pojo.constant.CodeConstants;
import com.innovation.ic.cc.base.pojo.constant.Constants;
import com.innovation.ic.cc.base.pojo.constant.LoginConstants;
import com.innovation.ic.cc.base.pojo.constant.handler.RedisStorage;
import com.innovation.ic.cc.base.pojo.enums.LoginTypeEnum;
import com.innovation.ic.cc.base.pojo.variable.AuthenticationUser;
import com.innovation.ic.cc.base.pojo.variable.ServiceResult;
import com.innovation.ic.cc.base.service.ServiceHelper;
import com.innovation.ic.cc.base.service.cc.LoginService;
import com.innovation.ic.cc.base.value.LoginConfig;
import com.innovation.ic.cc.base.value.RedisParamConfig;
import com.innovation.ic.cc.base.vo.login.BindThirdAccountVo;
import com.innovation.ic.cc.base.vo.login.SmsLoginVo;
import com.innovation.ic.cc.base.vo.user.UsersVo;
import org.apache.http.HttpStatus;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import javax.annotation.Resource;
import java.io.IOException;
import java.io.UnsupportedEncodingException;
import java.net.URLEncoder;

/**
 * @desc   loginService的实现类
 * @author linuo
 * @time   2022年8月8日16:04:24
 */
@Service
@Transactional
public class LoginServiceImpl implements LoginService {
    @Resource
    private LoginConfig loginConfig;

    @Resource
    private ServiceHelper serviceHelper;

    @Resource
    private RedisParamConfig redisParamConfig;

    /**
     * 通过短信验证码登录
     * @param smsLoginVo 短信验证码登录参数
     * @return 返回登录结果
     */
    @Override
    public ServiceResult<JSONObject> loginBySms(SmsLoginVo smsLoginVo) throws Exception {
        ServiceResult<JSONObject> serviceResult = new ServiceResult<>();
        Boolean success = Boolean.FALSE;
        JSONObject result = null;
        String message = null;

        // 调用erp9接口进行登录操作
        JSONObject param = (JSONObject) JSON.toJSON(smsLoginVo);
        String bandResult = HttpUtils.sendPost(loginConfig.getErpSmsLoginUrl(), param.toString());
        if(bandResult != null) {
            JSONObject jsonObject = (JSONObject) JSONObject.parse(bandResult);
            Integer status = jsonObject.getInteger(LoginConstants.STATUS_FIELD);
            String data = jsonObject.getString(LoginConstants.DATA);
            Boolean successResult = jsonObject.getBoolean(LoginConstants.SUCCESS_FIELD);

            // 登录成功
            if(status == null && successResult){
                success = Boolean.TRUE;
                message = "登录成功";
                String token = (String) jsonObject.get(LoginConstants.TOKEN);
                if(!Strings.isNullOrEmpty(token)){
                    // 通过token创建登录返回结果
                    result = createLoginResultByToken(token);
                }
            }

            // 登录失败
            if(status != null && (status.toString().equals(String.valueOf(HttpStatus.SC_INTERNAL_SERVER_ERROR)) || status.toString().equals(String.valueOf(CodeConstants.UN_BOUNDED)))){
                if(!Strings.isNullOrEmpty(data)){
                    message = data;
                }else{
                    message = jsonObject.getString(LoginConstants.MSG);
                }

                result = new JSONObject();
                result.put(LoginConstants.STATUS, status);
            }
        }

        serviceResult.setSuccess(success);
        serviceResult.setMessage(message);
        serviceResult.setResult(result);
        return serviceResult;
    }

    /**
     * 获取支付宝登录授权地址
     * @return 返回支付宝登录授权地址
     */
    @Override
    public ServiceResult<String> getAlipayAuthUrl(String redirectUrl) throws UnsupportedEncodingException {
        ServiceResult<String> serviceResult = new ServiceResult<>();
        serviceResult.setSuccess(Boolean.TRUE);

        // 对回调地址进行加密
        String encodeStr = URLEncoder.encode(redirectUrl,"UTF-8");

        serviceResult.setResult(AlipayHandler.getAuthUrl(loginConfig.getGetAuthUrl(), encodeStr));
        serviceResult.setMessage(ServiceResult.SELECT_SUCCESS);
        return serviceResult;
    }

    /**
     * 获取微信登录授权地址
     * @return 返回微信登录授权地址
     */
    @Override
    public ServiceResult<String> getWechatAuthUrl(String redirectUrl) throws UnsupportedEncodingException {
        ServiceResult<String> serviceResult = new ServiceResult<>();
        serviceResult.setSuccess(Boolean.TRUE);

        // 对回调地址进行加密
        String encodeStr = URLEncoder.encode(redirectUrl,"UTF-8");

        serviceResult.setResult(WechatHandler.getAuthUrl(loginConfig.getGetAuthUrl(), encodeStr));
        serviceResult.setMessage(ServiceResult.SELECT_SUCCESS);
        return serviceResult;
    }

    /**
     * 获取QQ登录授权地址
     * @param redirectUrl 回调地址
     * @return 返回QQ登录授权地址
     */
    @Override
    public ServiceResult<String> getQQAuthUrl(String redirectUrl) throws UnsupportedEncodingException {
        ServiceResult<String> serviceResult = new ServiceResult<>();
        serviceResult.setSuccess(Boolean.TRUE);

        // 对回调地址进行加密
        String encodeStr = URLEncoder.encode(redirectUrl,"UTF-8");

        serviceResult.setResult(QQHandler.getAuthUrl(loginConfig.getGetAuthUrl(), encodeStr));
        serviceResult.setMessage(ServiceResult.SELECT_SUCCESS);
        return serviceResult;
    }

    /**
     * 微信登录
     * @param authCode 临时授权码
     * @return 返回登录结果及登录信息
     */
    @Override
    public ServiceResult<JSONObject> loginByWechat(String authCode) {
        ServiceResult<JSONObject> serviceResult = new ServiceResult<>();
        Boolean success = Boolean.FALSE;
        JSONObject result = new JSONObject();
        String message = null;

        // 通过临时授权码获取用户个人信息
        JSONObject jsonObject = ErpHandler.loginByAuthCode(loginConfig.getLoginUrl(), authCode, LoginTypeEnum.WECHAT.getCode());
        if(jsonObject != null){
            Integer status = jsonObject.getInteger(LoginConstants.STATUS_FIELD);

            // 登录成功
            if(status != null && status == HttpStatus.SC_OK){
                success = Boolean.TRUE;

                JSONObject data = (JSONObject) jsonObject.get(LoginConstants.RESULT);
                if (data != null) {
                    String token = (String) data.get(LoginConstants.TOKEN);
                    // 通过token创建登录返回结果
                    result = createLoginResultByToken(token);
                }
            }

            // 登录失败
            if(status != null && status == HttpStatus.SC_INTERNAL_SERVER_ERROR){
                message = jsonObject.getString(LoginConstants.MESSAGE);
                result.put(LoginConstants.STATUS, HttpStatus.SC_INTERNAL_SERVER_ERROR);
            }

            // 账号未绑定
            if(status != null && status == CodeConstants.UN_BOUNDED){
                message = jsonObject.getString(LoginConstants.MESSAGE);
                result.put(LoginConstants.OPEN_ID, jsonObject.getString(LoginConstants.OPEN_ID));
                result.put(LoginConstants.UNION_ID, jsonObject.getString(LoginConstants.UNION_ID));
                result.put(LoginConstants.STATUS, CodeConstants.UN_BOUNDED);
            }
        }

        serviceResult.setSuccess(success);
        serviceResult.setResult(result);
        serviceResult.setMessage(message);
        return serviceResult;
    }

    /**
     * QQ登录
     * @param authCode 临时授权码
     * @return 返回登录结果及登录信息
     */
    @Override
    public ServiceResult<JSONObject> loginByQQ(String authCode) {
        ServiceResult<JSONObject> serviceResult = new ServiceResult<>();
        Boolean success = Boolean.FALSE;
        JSONObject result = new JSONObject();
        String message = null;

        // 通过临时授权码获取用户个人信息
        JSONObject jsonObject = ErpHandler.loginByAuthCode(loginConfig.getLoginUrl(), authCode, LoginTypeEnum.QQ.getCode());
        if(jsonObject != null){
            Integer status = jsonObject.getInteger(LoginConstants.STATUS_FIELD);

            // 登录成功
            if(status != null && status == HttpStatus.SC_OK){
                success = Boolean.TRUE;

                JSONObject data = (JSONObject) jsonObject.get(LoginConstants.RESULT);
                if (data != null) {
                    String token = (String) data.get(LoginConstants.TOKEN);
                    // 通过token创建登录返回结果
                    result = createLoginResultByToken(token);
                }
            }

            // 登录失败
            if(status != null && status == HttpStatus.SC_INTERNAL_SERVER_ERROR){
                message = jsonObject.getString(LoginConstants.MESSAGE);
                result.put(LoginConstants.STATUS, HttpStatus.SC_INTERNAL_SERVER_ERROR);
            }

            // 账号未绑定
            if(status != null && status == CodeConstants.UN_BOUNDED){
                message = jsonObject.getString(LoginConstants.MESSAGE);
                result.put(LoginConstants.OPEN_ID, jsonObject.getString(LoginConstants.OPEN_ID));
                result.put(LoginConstants.STATUS, CodeConstants.UN_BOUNDED);
            }
        }

        serviceResult.setSuccess(success);
        serviceResult.setResult(result);
        serviceResult.setMessage(message);
        return serviceResult;
    }

    /**
     * 绑定第三方账户
     * @param bindThirdAccountVo 绑定第三方账号的Vo类
     * @return 返回绑定结果
     */
    @Override
    public ServiceResult<JSONObject> bindThirdAccount(BindThirdAccountVo bindThirdAccountVo) throws IOException {
        ServiceResult<JSONObject> serviceResult = new ServiceResult<>();
        Boolean success = Boolean.FALSE;
        JSONObject result = new JSONObject();
        String message = null;

        // 调用erp接口进行第三方账户绑定操作
        JSONObject param = (JSONObject) JSON.toJSON(bindThirdAccountVo);
        String bandResult = HttpUtils.sendPost(loginConfig.getBandUrl(), param.toString());
        if(bandResult != null){
            JSONObject parse = (JSONObject) JSONObject.parse(bandResult);
            if(parse != null){
                Integer status = parse.getInteger(LoginConstants.STATUS_FIELD);

                // 成功
                if(status == HttpStatus.SC_OK){
                    message = "绑定成功";
                    success = Boolean.TRUE;

                    // 调用ERP登录接口进行登录操作
                    JSONObject jsonObject = loginThroughErp(bindThirdAccountVo);
                    if(jsonObject != null){
                        result = jsonObject.getJSONObject(Constants.RESULT);
                    }else{
                        message = "绑定失败,请重试";
                    }
                }

                // 将失败信息返回给前端响应
                if(status == HttpStatus.SC_INTERNAL_SERVER_ERROR){
                    message = "绑定失败,请重试";
                    String msg = parse.getString(LoginConstants.MSG);
                    if(!Strings.isNullOrEmpty(msg)){
                        message = msg;
                    }
                }
            }
        }

        serviceResult.setSuccess(success);
        serviceResult.setResult(result);
        serviceResult.setMessage(message);
        return serviceResult;
    }

    /**
     * 解绑第三方账户
     * @param type 解绑账号类型(0 微信、1 QQ、3 支付宝)
     * @param userId 用户id
     * @return 返回解绑结果
     */
    @Override
    public ServiceResult<JSONObject> unBindThirdAccount(String type, String userId) {
        ServiceResult<JSONObject> serviceResult = new ServiceResult<>();
        Boolean success = Boolean.FALSE;
        JSONObject result = new JSONObject();
        String message = null;

        // 调用erp接口进行第三方账户解绑操作
        JSONObject param = new JSONObject();
        param.put(LoginConstants.TYPE, type);
        param.put(LoginConstants.USER_ID_FIELD, userId);
        String bandResult = HttpUtils.sendPost(loginConfig.getUnBandUrl(), param.toString());
        if(bandResult != null){
            JSONObject parse = (JSONObject) JSONObject.parse(bandResult);
            if(parse != null){
                Integer status = parse.getInteger(LoginConstants.STATUS_FIELD);
                result.put(LoginConstants.STATUS_FIELD, status);

                // 成功
                if(status == HttpStatus.SC_OK){
                    message = "解绑成功";
                    success = Boolean.TRUE;
                }else{
                    message = "绑定失败,请重试";
                }
            }
        }

        serviceResult.setSuccess(success);
        serviceResult.setResult(result);
        serviceResult.setMessage(message);
        return serviceResult;
    }

    /**
     * 支付宝登录
     * @param authCode 临时授权码
     * @return 返回登录结果及登录信息
     */
    @Override
    public ServiceResult<JSONObject> loginByAlipay(String authCode) {
        ServiceResult<JSONObject> serviceResult = new ServiceResult<>();
        Boolean success = Boolean.FALSE;
        JSONObject result = new JSONObject();
        String message = null;

        // 通过临时授权码获取用户个人信息
        JSONObject jsonObject = ErpHandler.loginByAuthCode(loginConfig.getLoginUrl(), authCode, LoginTypeEnum.ALIPAY.getCode());
        if(jsonObject != null){
            Integer status = jsonObject.getInteger(LoginConstants.STATUS_FIELD);

            // 登录成功
            if(status != null && status == HttpStatus.SC_OK){
                success = Boolean.TRUE;

                JSONObject data = (JSONObject) jsonObject.get(LoginConstants.RESULT);
                if (data != null) {
                    String token = (String) data.get(LoginConstants.TOKEN);
                    // 通过token创建登录返回结果
                    result = createLoginResultByToken(token);
                }
            }

            // 登录失败
            if(status != null && status == HttpStatus.SC_INTERNAL_SERVER_ERROR){
                message = jsonObject.getString(LoginConstants.MESSAGE);
                result.put(LoginConstants.STATUS, HttpStatus.SC_INTERNAL_SERVER_ERROR);
            }

            // 账号未绑定
            if(status != null && status == CodeConstants.UN_BOUNDED){
                message = jsonObject.getString(LoginConstants.MESSAGE);
                result.put(LoginConstants.OPEN_ID, jsonObject.getString(LoginConstants.OPEN_ID));
                result.put(LoginConstants.STATUS, CodeConstants.UN_BOUNDED);
            }
        }

        serviceResult.setSuccess(success);
        serviceResult.setResult(result);
        serviceResult.setMessage(message);
        return serviceResult;
    }

    /**
     * 将AuthenticationUser对象存储到redis中，key为token，value是json字符串
     * @param authenticationUser 接收用户信息vo类
     */
    private void setAuthenticationUser(AuthenticationUser authenticationUser) {
        serviceHelper.getRedisManager().set(RedisStorage.TOKEN_PREFIX + authenticationUser.getToken(), JSON.toJSONString(authenticationUser));
        serviceHelper.getRedisManager().expire(RedisStorage.TOKEN_PREFIX + authenticationUser.getToken(), redisParamConfig.getTokenTimeout());
    }

    /**
     * 通过token创建登录返回结果
     * @param token token
     * @return 返回登录结果
     */
    private JSONObject createLoginResultByToken(String token){
        if(Strings.isNullOrEmpty(token)){
            return new JSONObject();
        }

        // 将token对象转换为接收用户信息vo类对象
        AuthenticationUser authenticationUser = AuthenticationUserHandler.toAuthenticationUser(token);

        // 将用户信息存储到redis中
        this.setAuthenticationUser(authenticationUser);

        return (JSONObject) JSON.toJSON(authenticationUser);
    }

    /**
     * 调用ERP登录接口进行登录操作
     * @param bindThirdAccountVo 绑定第三方账号的Vo类
     * @return 返回登录用户信息
     */
    private JSONObject loginThroughErp(BindThirdAccountVo bindThirdAccountVo) throws IOException {
        UsersVo usersVo = new UsersVo();
        usersVo.setUserName(bindThirdAccountVo.getUserName());
        usersVo.setPassword(bindThirdAccountVo.getPassWord());
        String result = HttpUtils.doPostTestTwo(loginConfig.getUrl(), JSON.toJSONString(usersVo));
        if(!Strings.isNullOrEmpty(result)) {
            JSONObject json = (JSONObject) JSONObject.parse(result);
            Integer status = json.getInteger(LoginConstants.STATUS_FIELD);
            // 成功
            if(status == HttpStatus.SC_OK) {
                JSONObject jsonObject = new JSONObject();
                JSONObject data = (JSONObject) json.get(LoginConstants.DATA);
                if (data != null) {
                    String token = (String) data.get(LoginConstants.TOKEN);
                    // 将token对象转换为接收用户信息vo类对象
                    AuthenticationUser authenticationUser = AuthenticationUserHandler.toAuthenticationUser(token);
                    if (authenticationUser != null) {

                        // 将用户信息存储到redis中
                        this.setAuthenticationUser(authenticationUser);

                        jsonObject.put(Constants.RESULT, JSON.toJSON(authenticationUser));
                    }
                    jsonObject.put(LoginConstants.STATUS_FIELD, status);
                }
                return jsonObject;
            }
        }
        return null;
    }
}